package com.zh.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zh.common.ErrorCode;
import com.zh.constant.RequirementConstant;
import com.zh.domain.dto.iteration.AddIterationRequest;
import com.zh.domain.dto.iteration.UpdateIterationRequest;
import com.zh.domain.entity.*;
import com.zh.domain.vo.iteration.IterationVo;
import com.zh.domain.vo.requirement.RequirementVo;
import com.zh.domain.vo.task.TaskCountVo;
import com.zh.domain.vo.task.TaskVo;
import com.zh.domain.vo.user.UserVO;
import com.zh.exception.ThrowUtils;
import com.zh.job.TaskManager;
import com.zh.service.*;
import com.zh.mapper.IterationMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Administrator
 * @description 针对表【iterations(迭代表)】的数据库操作Service实现
 * @createDate 2025-02-09 16:24:10
 */
@Service
@Slf4j
public class IterationServiceImpl extends ServiceImpl<IterationMapper, Iteration>
        implements IterationService {
    @Resource
    private IterationMapper iterationMapper;
    @Resource
    private UserService userService;
    @Resource
    private ProjectService projectService;
    @Resource
    private ProjectUserService projectUserService;
    @Resource
    private ProjectDynamicsService projectDynamicsService;
    @Resource
    private MessageService messageService;
    @Resource
    @Lazy
    private MilestoneService milestoneService;
    @Resource
    private RequirementsService requirementsService;
    @Resource
    private TaskService taskService;

    @Override
    public Boolean addIteration(AddIterationRequest addIterationRequest) {
        int loginId = StpUtil.getLoginIdAsInt();
        IterationService proxy = (IterationService) AopContext.currentProxy();
        //1.参数校验
        Integer proId = addIterationRequest.getProId();
        Integer mileId = addIterationRequest.getMileId();
        String title = addIterationRequest.getTitle();
        String description = addIterationRequest.getDescription();
        String remark = addIterationRequest.getRemark();
        LocalDateTime startTime = addIterationRequest.getStartTime();
        LocalDateTime endTime = addIterationRequest.getEndTime();
        ThrowUtils.throwIf(null == proId, ErrorCode.PARAMS_ERROR, "项目id不能为空");
        ThrowUtils.throwIf(startTime.isAfter(endTime), ErrorCode.PARAMS_ERROR, "开始时间不能大于结束时间");
        //2.时间校验-不能重叠,且必须在里程碑范围内
        checkTime(startTime, endTime, mileId);
        //3.获取编号 编号规则:I-proId-count 保存
        LambdaQueryWrapper<Iteration> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Iteration::getProId, proId);
        Long count = iterationMapper.selectCount(queryWrapper);
        Iteration iteration = BeanUtil.copyProperties(addIterationRequest, Iteration.class);
        iteration.setCode("I-" + "P" + proId + "-" + "M" + mileId + "-" + count.intValue() + 1);
        iteration.setProgress(BigDecimal.ZERO);
        iteration.setCreateAt(LocalDateTime.now());
        iteration.setCreateBy(loginId);
        iteration.setUpdateAt(LocalDateTime.now());
        iteration.setUpdateBy(loginId);
        iteration.setStatus(1);
        iteration.setDeleted(0);
        boolean saved = proxy.save(iteration);
        //4.保存项目动态 发送消息
        TaskManager.execute(() -> proxy.sendMessageAndDynamicWhenAdd(iteration));
        return saved;
    }

    @Override
    @Transactional
    public void sendMessageAndDynamicWhenAdd(Iteration iteration) {
        int loginId = StpUtil.getLoginIdAsInt();
        Integer createBy = iteration.getCreateBy();
        UserVO creator = userService.getUserVoById(createBy);
        ProjectDynamics dynamics = new ProjectDynamics(true);
        dynamics.setProId(iteration.getProId());
        String content;
        content = creator.getName() + "创建了迭代" + iteration.getTitle() + "-" + iteration.getCode() + '.';
        dynamics.setContent(content);
        projectDynamicsService.save(dynamics);
        //发送消息
        LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectUser::getProId, iteration.getProId());
        List<ProjectUser> projectUserList = projectUserService.list(queryWrapper);
        List<Integer> userIdList = projectUserList.stream().map(ProjectUser::getUserId).collect(Collectors.toList());
        Project project = projectService.getById(iteration.getProId());
        Message message = new Message();
        String messageContent = project.getTitle() + "-" + creator.getName() +
                " 创建了迭代-" +
                iteration.getTitle() +
                ".";
        message.setContent(messageContent);
        message.setSendId(creator.getId());
        message.setCreateAt(LocalDateTime.now());
        message.setCreateBy(loginId);
        message.setUpdateAt(LocalDateTime.now());
        message.setUpdateBy(loginId);
        message.setNoticeType(0);
        message.setType(2);
        message.setParams(Map.of(
                "iterId", iteration.toString(),
                "payloadType", "project",
                "title", iteration.getTitle()
        ));
        message.setStatus(1);
        message.setDeleted(0);
        messageService.sendMessage(message, userIdList);
    }

    @Override
    public List<IterationVo> listByMilestoneId(Integer mileStoneId) {
        if (mileStoneId == null) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<Iteration> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Iteration::getMileId, mileStoneId)
                .eq(Iteration::getDeleted, 0)
                .orderBy(true, true, Iteration::getId)
                .orderBy(true, true, Iteration::getStartTime);
        List<Iteration> iterationList = iterationMapper.selectList(queryWrapper);
        //获取用户信息
        List<Integer> userIdList = iterationList.stream()
                .flatMap(iteration -> Stream.of(iteration.getCreateBy()))
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        Map<Integer, UserVO> userVOMap = userService.listUserVoByIds(userIdList).stream()
                .collect(Collectors.toMap(UserVO::getId, userVO -> userVO));
        return iterationList.stream().map(iteration -> {
            IterationVo iterationVo = BeanUtil.copyProperties(iteration, IterationVo.class);
            List<RequirementVo> requirementVoList = requirementsService.listByIterationId(iteration.getId());
            List<TaskVo> taskVoList = taskService.listByIterationIdDirectly(iteration.getId());
            iterationVo.setCreator(userVOMap.get(iteration.getCreateBy()));
            iterationVo.setRequirementVoList(requirementVoList);
            iterationVo.setTaskVoList(taskVoList);
            return iterationVo;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public Boolean updateIteration(UpdateIterationRequest updateIterationRequest) {
        int loginId = StpUtil.getLoginIdAsInt();
        return updateIteration(loginId, updateIterationRequest);
    }

    @Override
    @Transactional
    public Boolean updateIteration(Integer userId, UpdateIterationRequest updateIterationRequest) {
        Integer loginId = userId;
        Integer id = updateIterationRequest.getId();
        Integer mileId = updateIterationRequest.getMileId();
        Integer status = updateIterationRequest.getStatus();
        String title = updateIterationRequest.getTitle();
        String description = updateIterationRequest.getDescription();
        String remark = updateIterationRequest.getRemark();
        LocalDateTime startTime = updateIterationRequest.getStartTime();
        LocalDateTime endTime = updateIterationRequest.getEndTime();
        ThrowUtils.throwIf(null == id, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(startTime != null && endTime != null && startTime.isAfter(endTime), ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(null != status && !RequirementConstant.isValidStatus(status), ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(null != title && title.length() > 100, ErrorCode.PARAMS_ERROR, "标题长度不能超过100");
        ThrowUtils.throwIf(null != description && description.length() > 20000, ErrorCode.PARAMS_ERROR, "描述长度不能超过20000");
        synchronized (id) {
            Iteration updateIteration = new Iteration();
            LambdaUpdateWrapper<Iteration> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Iteration::getId, id);
            if (mileId != null && mileId != -1) {
                updateWrapper.set(Iteration::getMileId, mileId);
            } else if (mileId == null) {
                updateWrapper.set(Iteration::getMileId, null);
            }
            updateWrapper.set(null != title, Iteration::getTitle, title);
            updateWrapper.set(null != description, Iteration::getDescription, description);
            updateWrapper.set(null != remark, Iteration::getRemark, remark);
            updateWrapper.set(null != startTime, Iteration::getStartTime, startTime);
            updateWrapper.set(null != endTime, Iteration::getEndTime, endTime);
            updateWrapper.set(Iteration::getUpdateAt, LocalDateTime.now());
            updateWrapper.set(Iteration::getUpdateBy, loginId);

            updateWrapper.set(null != status, Iteration::getStatus, status);
            if (status != null && 4 == status) {
                updateWrapper.eq(Iteration::getCompleteTime, LocalDateTime.now());
            }
            return iterationMapper.update(updateIteration, updateWrapper) > 0;
        }
    }

    @Override
    public IterationVo getDetail(Integer id) {
        Iteration iteration = iterationMapper.selectById(id);
        if (null == iteration) {
            return null;
        }
        IterationVo iterationVo = BeanUtil.copyProperties(iteration, IterationVo.class);
        UserVO creator = userService.getUserVoById(iteration.getCreateBy());
        UserVO updater = userService.getUserVoById(iteration.getUpdateBy());

        List<TaskVo> taskVos = taskService.listByIterationIdDirectly(id);
        List<RequirementVo> requirementVos = requirementsService.listByIterationId(id);
        iterationVo.setCreator(creator);
        iterationVo.setUpdater(updater);
        iterationVo.setTaskVoList(taskVos);
        iterationVo.setRequirementVoList(requirementVos);
        return iterationVo;
    }

    @Override
    @Transactional
    public void updateProcessById(Integer id) {
        List<TaskVo> taskVoList = taskService.listByIterationId(id);
        if (CollectionUtil.isEmpty(taskVoList)) {
            return;
        }
        long completeCount = taskVoList.stream().filter(taskVo -> taskVo.getStatus() == 4).count();
        BigDecimal progress = new BigDecimal(completeCount).divide(new BigDecimal(taskVoList.size()), 2, RoundingMode.HALF_UP);
        //3.更新需求进度 若需求进度为100%，则更新需求状态为已完成
        Iteration iteration = new Iteration();
        if (progress.compareTo(BigDecimal.valueOf(1)) == 0) {
            iteration.setStatus(4);
            iteration.setCompleteTime(LocalDateTime.now());
        }
        iteration.setId(id);
        iteration.setProgress(progress);
        iteration.setUpdateAt(LocalDateTime.now());
        iterationMapper.updateById(iteration);
        log.info("更新迭代-{}-进度-{}", id, progress);
    }

    @Override
    public TaskCountVo getTaskCount(Integer iterId) {
        List<TaskVo> taskVoList = taskService.listByProId(iterId);
        TaskCountVo taskCountVo = new TaskCountVo();
        taskCountVo.setIterId(iterId);

        int totalTask = 0;
        int doneTask = 0;
        int doingTask = 0;
        int undoTask = 0;
        int unStartTask = 0;
        int overdueTask = 0;
        int todayTask = 0;
        double process = 0.0;
        double overDueRate = 0.0;
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        for (TaskVo taskVo : taskVoList) {
            totalTask++;
            int status = taskVo.getStatus();
            switch (status) {
                case 0: // 规划中
                    unStartTask++;
                    break;
                case 1: // 进行中
                    doingTask++;
                    break;
                case 3: // 已逾期
                    overdueTask++;
                    break;
                case 4: // 已完成
                    doneTask++;
                    break;
//                case 5: // 已废弃
//                    undoTask++;
//                    break;
                default:
                    undoTask++;
                    break;
            }

            // 判断今日到期任务
            if (taskVo.getEndTime() != null && taskVo.getEndTime().format(formatter).equals(now.format(formatter))) {
                todayTask++;
            }
        }
        // 计算完成进度和逾期率
        if (totalTask > 0) {
            process = (double) doneTask / totalTask;
            overDueRate = (double) overdueTask / totalTask;
        }
        taskCountVo.setTotalTask(totalTask);
        taskCountVo.setDoneTask(doneTask);
        taskCountVo.setDoingTask(doingTask);
        taskCountVo.setUndoTask(undoTask);
        taskCountVo.setUnStartTask(unStartTask);
        taskCountVo.setOverdueTask(overdueTask);
        taskCountVo.setTodayTask(todayTask);
        taskCountVo.setProcess(process);
        taskCountVo.setOverDueRate(overDueRate);
        return taskCountVo;
    }

    private void checkTime(LocalDateTime startTime, LocalDateTime endTime, Integer mileId) {
        if (startTime == null || endTime == null) {
            return;
        }

        // 获取里程碑的时间范围
        Milestone milestone = milestoneService.getById(mileId);
        if (milestone == null) {
            throw new IllegalArgumentException("里程碑不存在");
        }
        LocalDateTime milestoneStartTime = milestone.getStartTime();
        LocalDateTime milestoneEndTime = milestone.getEndTime();

        // 检查新迭代的时间范围是否在里程碑的时间范围内
        ThrowUtils.throwIf(startTime.isBefore(milestoneStartTime) || endTime.isAfter(milestoneEndTime), ErrorCode.PARAMS_ERROR, "时间范围不能超出里程碑的时间范围");
        // 获取同一里程碑下的所有迭代
        LambdaQueryWrapper<Iteration> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Iteration::getMileId, mileId)
                .eq(Iteration::getDeleted, 0);
        List<Iteration> existingIterations = iterationMapper.selectList(queryWrapper);

        // 检查新迭代的时间范围是否与现有迭代的时间范围重叠
        for (Iteration existingIteration : existingIterations) {
            LocalDateTime existingStartTime = existingIteration.getStartTime();
            LocalDateTime existingEndTime = existingIteration.getEndTime();
            ThrowUtils.throwIf(startTime.isBefore(existingEndTime) && endTime.isAfter(existingStartTime), ErrorCode.PARAMS_ERROR, "时间范围不能重叠");
        }
    }
}



